<template>
  <div class="container">
    <!-- 左侧扫描输入 -->
    <div class="panel">
      <!-- 下载链接 + 打印机选择（同一行） -->
      <div style="display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px;">
        <el-link type="primary" href="https://www.lodop.net/download/CLodop_Setup_for_Win64NT_6.623EN.zip"
                 target="_blank">
          请先下载 CLodop 安装程序
        </el-link>

        <el-select v-model="selectedPrinter" placeholder="选择打印机" size="small" style="width: 200px;">
          <el-option v-for="printer in printers" :key="printer.index" :label="printer.name" :value="printer.index"/>
        </el-select>
      </div>

      <div style="margin-top: 16px;">
        <el-row :gutter="24" align="middle">
          <el-col :span="5">
            <el-form-item>
              <el-checkbox v-model="pdfToImageEnabled">PDF转图片打印</el-checkbox>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="24" align="middle">
          <el-col :span="5">
            <el-form-item label="宽度">
              <el-input
                  v-model="paperWidth"
                  :disabled="!pdfToImageEnabled"

                  size="small"
              >
                <template #append>mm</template>
              </el-input>

            </el-form-item>
          </el-col>

          <el-col :span="5">
            <el-form-item label="高度">
              <el-input
                  v-model="paperHeight"
                  :disabled="!pdfToImageEnabled"

                  size="small"
              >
                <template #append>mm</template>
              </el-input>
            </el-form-item>
          </el-col>

          <el-col :span="5">
            <el-form-item label="DPI">
              <el-input
                  v-model="dpi"
                  :disabled="!pdfToImageEnabled"

                  size="small"
              >

                <template #append>dpi</template>
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item label="X">
              <el-input
                  v-model="offsetX"
                  :disabled="true"

                  size="small"
              >

                <template #append>px</template>
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item label="Y">
              <el-input
                  v-model="offsetY"
                  :disabled="true"

                  size="small"
              >

                <template #append>px</template>
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="24" align="middle">

        </el-row>
      </div>

      <h3>扫描单号打印</h3>

      <el-input v-model="scanCode" placeholder="请扫描或输入单号" @keyup.enter="onScan" clearable autofocus
                size="large">
        <template #append>
          <el-button type="primary" @click="onScan">打印</el-button>
        </template>
      </el-input>


      <!-- 扫描历史记录 -->
      <el-table :data="scanHistory" size="small" border style="margin-top: 20px; max-height: 500px; overflow: auto;">
        <el-table-column prop="code" label="单号" width="150"/>
        <el-table-column label="PDF链接">
          <template #default="{ row }">
            <el-link :href="row.url" target="_blank" type="primary">查看</el-link>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <!-- 右侧预览区域 -->
    <div class="panel preview-panel">
      <div class="preview-header">
        <h3>打印预览</h3>
        <div v-if="previewList.length" class="toolbar">
          <el-button-group>
            <el-button icon="RefreshRight" @click="rotateRight">旋转</el-button>
            <el-button icon="ZoomIn" @click="zoomIn">放大</el-button>
            <el-button icon="ZoomOut" @click="zoomOut">缩小</el-button>
            <el-button icon="Refresh" @click="resetTransform">重置</el-button>
          </el-button-group>
        </div>
      </div>

      <div class="preview-body" v-loading="loading">
        <div v-if="!previewList.length" class="preview-empty">请扫描单号后预览</div>

        <div v-else class="preview-content" :style="{ transform: `scale(${scale}) rotate(${rotate}deg)` }">
          <iframe v-if="currentItem.type === 'pdf' || currentItem.type === 'PDF'" :src="currentItem.base64Str"
                  frameborder="0"
                  class="preview-frame" allowfullscreen ></iframe>
          <img
              v-else-if="currentItem.type === 'image' || currentItem.type === 'png' || currentItem.type === 'jepg' || currentItem.type === 'jpg'"
              :src="currentItem.base64Str" alt="预览图片" class="preview-img"/>
        </div>

        <!-- 切换多张 -->
        <div v-if="previewList.length > 1" class="page-control">
          <el-button @click="prevPage" :disabled="currentIndex === 0">上一张</el-button>
          <span>第 {{ currentIndex + 1 }} / {{ previewList.length }} 张</span>
          <el-button @click="nextPage" :disabled="currentIndex === previewList.length - 1">下一张</el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import {queryOrderPrint, signPrint} from '@/api';
import {createLodopInstance} from '@/utils/useLodop';
import {ElMessage} from 'element-plus';
import {useUserStore} from '@/store/user';
import {useSpeech} from '@/utils/useSpeech';

export default {
  name: 'LabelPrint',
  data() {
    return {
      scanCode: '',
      previewList: [],
      currentIndex: 0,
      loading: false,
      rotate: 0,
      scale: 1,
      httpLodop: null,
      httpLodops: null,
      printing: false,
      printers: [],
      selectedPrinter: 0,
      scanHistory: [],
      userStore: useUserStore(),
      blobUrls: [], // 存储所有生成过的 Blob URL，便于统一释放
      useSpeech: useSpeech(),
      pdfToImageEnabled: false,
      paperWidth: 101.6,
      paperHeight: 152.4,
      dpi: 300,
      offsetX : 0,
      offsetY : 30
    };
  },
  computed: {
    currentItem() {
      return this.previewList[this.currentIndex] || {};
    },
  },
  created() {
    this.initLodop();
  },
  methods: {
    filterFloatInput(value, maxIntegerLen = 3, maxDecimalLen = 2) {
      // 移除非数字和点
      let cleaned = value.replace(/[^\d.]/g, '');

      // 保留第一个小数点
      const parts = cleaned.split('.');
      let integer = parts[0].slice(0, maxIntegerLen);
      let decimal = parts[1] ? parts[1].slice(0, maxDecimalLen) : '';

      return decimal ? `${integer}.${decimal}` : integer;
    },

    async onScan() {

      this.revokeBlobUrls();

      if (!this.printers || this.printers.length === 0){
        this.$message.warning('未检测到打印机,请检查Loodp是否准备就绪');
        return;
      }


      if (this.printing) {
        this.$message.warning('正在打印中，请稍后再试');
        return;
      }

      if (this.pdfToImageEnabled) {
        // 判断 paperWidth、paperHeight、dpi 是否为空或非数字
        const isInvalid = [this.paperWidth, this.paperHeight, this.dpi].some(val => {
          // 空值判断
          if (val === null || val === undefined || val === '') return true;
          // 数字判断（包括浮点数）
          return isNaN(Number(val));
        });

        if (isInvalid) {
          this.$message.warning('请输入有效的打印机纸张大小和DPI');
          return;
        }
      }

      const code = this.scanCode.trim();
      if (!code) {
        this.$message.warning('请输入或扫描单号');
        return;
      }

      if (!(this.httpLodop?.lodopReady)) {
        this.$message.error('未找到可用的 LODOP 服务,请检查是否安装驱动并且启动');
        return;
      }

      try {
        this.loading = true;
        const result = await this.fetchPreview(code);

        if (result.code !== 200) {
          this.useSpeech.speak(result.message)
          return
        }

        const data = result.data

        if (!data || !data?.order_id) {
          this.useSpeech.speak("单号不存在")
          ElMessage.error('单号不存在');
          return;
        }

        if (!data.labelInfos || !data.labelInfos.length) {
          this.useSpeech.speak("未查询到面单")
          ElMessage.error('未查询到面单');
          return;
        }

        if (!data) {
          return
        }

        const dataList = data.labelInfos
        this.previewList = await Promise.all(
            dataList.map(async item => {
              //https不兼容，全部转成base64 后续需要用https的要改成http取掉打印驱动
              const base64Str = await this.downloadUrlToBase64(item.label_info);
              return {
                url: item.label_info,
                base64Str,
                type: item.label_type || 'pdf',
              };
            })
        );

        this.currentIndex = 0;

        this.$message.success(`开始打印单号：${code}`);

        // 逐条打印并记录历史（根据协议选用对应 lodop 实例）
        for (const item of this.previewList) {
          let lodop = null;
          lodop = this.httpLodop;
          // if (item.url.startsWith('https://') && this.httpsLodop?.lodopReady) {
          //   lodop = this.httpsLodop;
          // } else {
          //   lodop = this.httpLodop;
          // } 


          this.printing = true;
          const type = item.type.toLowerCase();
          if (type === 'pdf') {
            // if(item.url.startsWith('https://')){
            //   //转出http
            //   // lodop.printPdfUrl(item.origin_url.replace(/^https:/, 'http:'), this.selectedPrinter);
            //   lodop.printPdfFromUrlAsBase64(item.base64Str, this.selectedPrinter);
            // }else{
            //   lodop.printPdfUrl(item.origin_url, this.selectedPrinter);
            // }
            // lodop.printPdfUrl(item.url.replace(/^https:/, 'http:'), this.selectedPrinter);
            // lodop.printPdfBase64(item.base64Str, this.selectedPrinter);

            if (this.pdfToImageEnabled) {
              lodop.printPdfWithUserSize(item.base64Str, this.selectedPrinter, this.paperWidth, this.paperHeight, this.dpi, code);
              // await lodop.printBase64PdfForZpl(item.base64Str, this.selectedPrinter, this.paperWidth, this.paperHeight, this.dpi,this.offsetX,this.offsetY);
            } else {
              lodop.printPdfBase64(item.base64Str, this.selectedPrinter, code);
            }
          } else if (type === 'png' || type === 'jepg' || type === 'jpg') {
            lodop.printImageBase64(item.base64Str, this.selectedPrinter, code);
          } else {
            this.$message.warning('暂不支持此类型打印');
            this.printing = false;
            continue
          }

          this.scanHistory.push({code, url: item.url});
          this.printing = false;
        }


        //标记打印
        signPrint(data.order_id, this.userStore.getUser().user_id).then(data => {
          console.log("成功")
        })

        this.resetTransform();

      } catch (e) {
        console.log(e)
        this.$message.error('预览加载失败');
        this.loading = false;
      } finally {
        this.loading = false;
        this.scanCode = '';
      }


    },

    async initLodop() {
      this.httpLodop = createLodopInstance('http', 'localhost', 8000);
      await this.httpLodop.initLodop();

      //不需要https
      // this.httpsLodop = createLodopInstance('https', 'localhost.lodop.net', 8443);
      // await this.httpsLodop.initLodop();

      // if (!this.httpLodop.lodopReady && !this.httpsLodop.lodopReady) {
      //   this.$message.error('LODOP 初始化失败: ' +
      //     (this.httpsLodop.lodopError || this.httpLodop.lodopError));
      // }

      if (!this.httpLodop.lodopReady) {
        this.$message.error('LODOP 初始化失败: ' +
            (this.httpLodop.lodopError));
      }

      // 优先从 httpsLodop 获取打印机（如果可用）
      // const readyLodop = this.httpsLodop.lodopReady ? this.httpsLodop : this.httpLodop;
      const readyLodop = this.httpLodop;
      this.printers = readyLodop.getPrinters?.() || [];
      if (this.printers.length > 0) {
        this.selectedPrinter = this.printers[0].index;
      }
    },

    async fetchPreview(code) {
      return await queryOrderPrint(code);
    },

    rotateRight() {
      this.rotate = (this.rotate + 90) % 360;
    },
    zoomIn() {
      this.scale += 0.1;
    },
    zoomOut() {
      this.scale = Math.max(0.1, this.scale - 0.1);
    },
    resetTransform() {
      this.scale = 1;
      this.rotate = 0;
    },
    nextPage() {
      if (this.currentIndex < this.previewList.length - 1) this.currentIndex++;
    },
    prevPage() {
      if (this.currentIndex > 0) this.currentIndex--;
    },
    async webUrl2BlobUrl(webUrl, options = {}) {
      const {fetchHeaders = {}, fileType = ''} = options;

      try {
        const response = await fetch(webUrl, {
          mode: 'cors',
          headers: fetchHeaders,
        });

        if (!response.ok) {
          // console.error(`Fetch 失败: HTTP ${response.status}`);
          return null;
        }

        const blob = await response.blob();

        // 推断或指定 MIME 类型
        const blobType = this.getMediaType(fileType) || blob.type || 'application/octet-stream';

        const finalBlob = new Blob([blob], {type: blobType});
        const blobUrl = URL.createObjectURL(finalBlob);

        this.blobUrls = this.blobUrls || [];
        this.blobUrls.push(blobUrl); // 保存用于后续释放

        return blobUrl;
      } catch (e) {
        // console.error('webUrl2BlobUrl 异常:', e);
        return null;
      }

    },
    revokeBlobUrls() {
      this.blobUrls.forEach(url => URL.revokeObjectURL(url));
      this.blobUrls = [];
    },
    getMediaType(fileType) {
      if (!fileType) return '';

      const mediaTypeMap = {
        pdf: 'application/pdf',
        jpg: 'image/jpeg',
        jpeg: 'image/jpeg',
        png: 'image/png',
      };

      return mediaTypeMap[fileType.toLowerCase()] || '';
    },
    async downloadUrlToBase64(url, withPrefix = true) {
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error(`请求失败：${response.status}`);

        const blob = await response.blob();
        const base64 = await this.blobToBase64(blob);

        if (!withPrefix) {
          // 去掉 data:xxx;base64, 前缀
          return this.removeBasePrefix(base64);
        }

        return base64;
      } catch (error) {
        console.error('转换失败:', error);
        return null;
      }
    },

    removeBasePrefix(data) {
      return data.replace(/^data:.*;base64,/, '')
    },
// 工具函数：Blob 转 base64
    blobToBase64(blob) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onloadend = () => resolve(reader.result);
        reader.onerror = reject;
        reader.readAsDataURL(blob);
      });
    }


  },
};
</script>

<style scoped>
.container {
  display: flex;
  height: 100%;
  min-height: 500px;
  border: 1px solid #fff;
  border-radius: 6px;
  overflow: hidden;
  background-color: #fff;
}

.panel {
  width: 50%;
  padding: 20px;
  box-sizing: border-box;
  border-right: 1px solid #ddd;
  /* display: flex; */
  flex-direction: column;
}

.panel:last-child {
  border-right: none;
}

.preview-panel {
  overflow: hidden;
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.toolbar {
  display: flex;
  gap: 8px;
}

.preview-body {
  flex: 1;
  position: relative;
  overflow: auto;
  margin-top: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  background: #f9f9f9;
}

.preview-empty {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #999;
}

.preview-content {
  width: 100%;
  height: 100%;
  transform-origin: center center;
  display: flex;
  justify-content: center;
  align-items: center;
}

.preview-frame {
  width: 100%;
  height: 600px;
  border: none;
}

.preview-img {
  max-width: 100%;
  max-height: 600px;
  object-fit: contain;
}

.page-control {
  text-align: center;
  margin-top: 10px;
  display: flex;
  justify-content: center;
  gap: 20px;
  align-items: center;
}

.unit-label {
  padding: 0 4px;
  font-size: 12px;
  min-width: 1em;
  white-space: nowrap;
}
</style>
